#include "I2C.h"

bool I2C::SendByte(uint8 data)
{
	for (size_t i = 0x80; i > 0; i >>= 1)
	{

		if (data & i)
			digitalWrite(this->_SDA, HIGH);
		else
			digitalWrite(this->_SDA, LOW);

		digitalWrite(this->_SCL, HIGH);
		digitalWrite(this->_SCL, LOW);
	}

	pinMode(this->_SDA, INPUT);
	digitalWrite(this->_SCL, HIGH);
	bool res = digitalRead(this->_SDA);
	pinMode(this->_SDA, OUTPUT);
	digitalWrite(this->_SCL, LOW);
	return res;
}

uint8 I2C::ReadByte(bool ACK)
{

	pinMode(this->_SDA, INPUT_PULLUP);
	uint8 data = 0;
	for (size_t i = 0x80; i > 0; i >>= 1)
	{
		digitalWrite(this->_SCL, LOW);
		digitalWrite(this->_SCL, HIGH);
		if (digitalRead(this->_SDA))
			data |= i;
	}
	digitalWrite(this->_SCL, LOW);
	pinMode(this->_SDA, OUTPUT);

	if (ACK)
		this->Ack();
	else
		this->NoAck();
	return data;
}

bool I2C::SendAddByte(uint8 addr, uint8 regaddr, uint8 data)
{
	this->Start();

	if (this->SendByte((addr << 1) | 0x00))
		goto end;

	if (this->SendByte(regaddr))
		goto end;

	if (this->SendByte(data))
		goto end;
	this->End();
	return true;
end:
	this->End();
	return false;
}

bool I2C::ReadAddByte(uint8 addr, uint8 regaddr, uint8& data)
{
	this->Start();

	if (this->SendByte((addr << 1) | 0x00))
		goto end;

	if (this->SendByte(regaddr))
		goto end;

	this->Start();

	if (this->SendByte((addr << 1) | 0x01))
		goto end;

	data = this->ReadByte(false);

	this->End();
	return true;
end:
	this->End();
	return false;
}

bool I2C::SendAddArr(uint8 addr, uint8 regaddr, uint8* databuf, uint8 lenth)
{
	this->Start();

	if (this->SendByte((addr << 1) | 0x00))
		goto end;

	if (this->SendByte(regaddr))
		goto end;

	for (size_t i = 0; i < lenth; i++)
	{
		if (this->SendByte(databuf[i]))
			goto end;
	}

	this->End();
	return true;
end:
	this->End();
	return false;
}

bool I2C::ReadAddArr(uint8 addr, uint8 regaddr, uint8* databuf, uint8 lenth)
{
	this->Start();

	if (this->SendByte((addr << 1) | 0x00))
		goto end;

	if (this->SendByte(regaddr))
		goto end;

	this->Start();

	if (this->SendByte((addr << 1) | 0x01))
		goto end;

	for (size_t i = 0; i < lenth - 1; i++)
		databuf[i] = this->ReadByte(true);

	databuf[lenth - 1] = this->ReadByte(false);
	this->End();
	return true;
end:
	this->End();
	return false;
}